CPPSTD		?= --std=c++20 
CPPFLAGS	+= $(CPPSTD)

SRCDIR	?= ./source
SRCEXT	?= .cpp
#SHARED

override	CPPFLAGS	+= -MMD -MP
override	CPPFLAGS	+= -I./include -I$(SRCDIR)
override	CPPFLAGS	+= $(shell cat .cxxflags 2> /dev/null | xargs)

ARFLAGS	:= $(ARFLAGS)c

INSTALL_INCLUDE ?= include
INSTALL_SOURCE ?= source
INSTALL_LIB	?= lib
#LOCAL_TEMP
#LOCAL_DIST

COPYRIGHT_FILE ?= ./COPYRIGHT
ifneq ($(shell cat $(COPYRIGHT_FILE) 2> /dev/null),)
COPYRIGHT ?= $(COPYRIGHT_FILE)
COPYRIGHT_DEP = $(COPYRIGHT_FILE)
else
COPYRIGHT ?= /dev/null
endif

PREFIX	?= $(DESTDIR)/usr/local
INCDIR	:= $(PREFIX)/$(INSTALL_INCLUDE)
LIBDIR	:= $(PREFIX)/$(INSTALL_LIB)
INSTALL_SRCDIR	:= $(PREFIX)/$(INSTALL_SOURCE)


TEMPDIR	:= temp
ifneq ($(LOCAL_TEMP),)
TEMPDIR	:= $(TEMPDIR)/$(LOCAL_TEMP)
endif

DISTDIR	:= out
ifneq ($(LOCAL_DIST),)
DISTDIR	:= $(DISTDIR)/$(LOCAL_DIST)
endif

ifneq ($(SHARED),)
LIBEXT	:= .so
override LOCALIB	+= $(wildcard lib/*.a)
override LDFLAGS	+= --shared
override LDFLAGS	+= $(shell cat .ldflags 2> /dev/null | xargs)
override LDFLAGS	+= -L./lib
override LDLIBS		+= $(shell cat .ldlibs 2> /dev/null | xargs)
else
LIBEXT	:= .a
endif

ifeq ($(origin NAME), undefined)
NAME	:= $(shell pwd | xargs basename)
endif

ifeq ($(origin TARGET), undefined)
TARGET	:= $(NAME)$(LIBEXT)
endif

OUT		:= $(DISTDIR)/$(TARGET)

ifeq ($(origin HEADERS), undefined)
HEADERS	:= $(shell find -wholename "$(SRCDIR)/*.hpp" && find -wholename "$(SRCDIR)/*.h")
endif
INCLUDE	:= $(ADD_INCLUDE:%=$(INCDIR)/%) $(HEADERS:$(SRCDIR)/%=$(INCDIR)/%)
INCDIRS	:= $(shell dirname $(INCLUDE) 2> /dev/null)

ifeq ($(origin SOURCES), undefined)
SOURCES	:= $(shell find -wholename "$(SRCDIR)/*$(SRCEXT)")
endif

OBJECTS	:= $(SOURCES:$(SRCDIR)/%$(SRCEXT)=$(TEMPDIR)/%.o)
OBJDIRS	:= $(shell dirname $(OBJECTS))
DEPENDS	:= $(OBJECTS:.o=.d)

INSTALL_SOURCES	:= $(SOURCES:$(SRCDIR)/%=$(INSTALL_SRCDIR)/%)
INSTALL_SOURCES	+= $(INCLUDE:$(INCDIR)/%=$(INSTALL_SRCDIR)/%)
INSTALL_SOURCES	+= $(ADD_INSTALL_SOURCES:%=$(INSTALL_SRCDIR)/%)
INSTALL_SRCDIRS	:= $(shell dirname $(INSTALL_SOURCES))

build: $(OUT)

$(DISTDIR)/%.a: $(OBJECTS) | $(DISTDIR)
	$(AR) $(ARFLAGS) $@ $^

$(DISTDIR)/%.so: $(OBJECTS) $(LOCALIB) | $(DISTDIR)
	$(CXX) $(LDFLAGS) $(OBJECTS) $(LOCALIB) $(LDLIBS) -o $@

$(TEMPDIR)/%.o: $(SRCDIR)/%$(SRCEXT) | $(TEMPDIR)
	@mkdir -p $(@D)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<

$(TEMPDIR):
	@mkdir -p $@

$(DISTDIR):
	@mkdir -p $@

clean:
	@rm $(DEPENDS) 2> /dev/null || true
	@rm $(OBJECTS) 2> /dev/null || true
	@rmdir -p $(OBJDIRS) 2> /dev/null || true
	@rmdir -p $(TEMPDIR) 2> /dev/null || true
	@echo Temporaries cleaned!

distclean: clean
	@rm $(OUT) 2> /dev/null || true
	@rmdir -p $(DISTDIR) 2> /dev/null || true
	@echo All clean!

install_all: install install_source

install: $(LIBDIR)/$(TARGET) $(INCLUDE)

$(LIBDIR)/$(TARGET): $(OUT) | $(LIBDIR)
	cp $< $@

$(LIBDIR):
	@mkdir -p $@

$(INCDIR)/%.h: $(SRCDIR)/%.h $(COPYRIGHT_DEP)
	@mkdir -p $(@D)
	cat $(COPYRIGHT) > $@
	cat $< >> $@

$(INCDIR)/%.hpp: $(SRCDIR)/%.hpp $(COPYRIGHT_DEP)
	@mkdir -p $(@D)
	cat $(COPYRIGHT) > $@
	cat $< >> $@

install_source: $(INSTALL_SOURCES)

$(INSTALL_SRCDIR)/%: $(SRCDIR)/% $(COPYRIGHT_DEP)
	@mkdir -p $(@D)
	cat $(COPYRIGHT) > $@
	cat $< >> $@

uninstall:
	-rm $(INCLUDE)
	@rmdir -p $(INCDIRS) 2> /dev/null || true
	-rm $(LIBDIR)/$(TARGET)
	@rmdir -p $(LIBDIR) 2> /dev/null || true
	@echo Archives/includes uninstalled!

uninstall_source:
	-rm $(INSTALL_SOURCES)
	@rmdir -p $(INSTALL_SRCDIRS) 2> /dev/null || true
	@echo Source code uninstalled!

uninstall_all: uninstall uninstall_source
	@echo Everything uninstalled!


-include $(DEPENDS)

ifneq ($(shell cat unit_tests/Makefile 2> /dev/null),)
TESTMAKE = +@$(MAKE) --no-print-directory -C unit_tests/ PARENT_DISTDIR=../$(DISTDIR) LOCAL_TEMP=$(LOCAL_TEMP) LOCAL_DIST=$(LOCAL_DIST)
else
TESTMAKE = -@true
endif

test: $(OUT)
	@$(TESTMAKE)

test-clean:
	@$(TESTMAKE) clean

test-cleanrun:
	@$(TESTMAKE) cleanrun
	@$(TESTMAKE) run

test-all: test-clean test

clean: test-clean

.PRECIOUS : $(OBJECTS)
.PHONY : build clean distclean uninstall uninstall_source uninstall_all test test-clean test-cleanrun test-all
